Compute Legendre symbol for hash_to_curve#77
Conversation
|
Could F::ZERO - F::ONE work (as value for MODULUS - 1)? |
|
Thanks for the suggestion @huitseeker! Updated in 3b7e8b3 |
huitseeker
left a comment
There was a problem hiding this comment.
It would be great to see a couple of tests. One curve-independent thing to test being the relationship between legendre and foo.sqrt().is_some().
Another thought it this is pinned on receiving p_minus_one, which is systematically divided by two during the computation. Could we possibly require the field definition to include a constant for (p-1)/2?
han0110
left a comment
There was a problem hiding this comment.
LGTM, also think it'd be nice to have (p-1)/2 as constant somewhere (perhaps some private helper trait).
|
Thanks for the reviews! I have added a couple of tests in 0b40c37 I agree with the comments regarding fixing |
CPerezz
left a comment
There was a problem hiding this comment.
Just one suggestion that not sure makes sense. Would like to at least discuss it.
| #[inline] | ||
| pub(crate) fn legendre<F: PrimeField>(elem: F, p_minus_one: BigUint) -> F { | ||
| let exp: BigUint = p_minus_one >> 1; | ||
| elem.pow(exp.to_u64_digits()) | ||
| } |
There was a problem hiding this comment.
Can't we pass P-1 to the macro invocation/function so that is treated as an asociated constant of F or similar? SO that we write this fn as a macro instead of a fn hence we get the constant for p_minus_one directly.
Another idea is to have a F::MINUS_ONE_AS_BIGUNT for each curve field. Being that implemented via any of the macros.
Then implement all of the legendre stuff inside of a macro for each of them having minus_one as ctant too.
I'd at least bench the difference and see if it makes sense.
| pub(crate) fn is_quadratic_non_residue<F: PrimeField>(e: F, p_minus_one: BigUint) -> Choice { | ||
| legendre(e, p_minus_one).ct_eq(&-F::ONE) | ||
| } |
| #[inline] | ||
| pub(crate) fn mod_minus_one<F: PrimeField>() -> BigUint { | ||
| BigUint::from_bytes_le((-F::ONE).to_repr().as_ref()) | ||
| } |
There was a problem hiding this comment.
This will not need to exist if we do what I suggested above. Or at least will only be useful at compile time in a lazy_static block or similar.
| let gx2 = gx2 + b; | ||
| // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops | ||
| let e2 = gx2.sqrt().is_some() & (!e1); | ||
| let e2 = !is_quadratic_non_residue(gx2, p_minus_one) & (!e1); |
There was a problem hiding this comment.
p_minus_one could be a constant.
|
I have tried to address the issue of pre-computing and passing around |
We are at a point that merging without benchmarks feels like an error. I don't want to land things in the codebase for which we don't know the performance implications. |
0b40c37 to
6bea1fe
Compare
|
I have added the changes from #79 here and I've also added some benchmarks as @CPerezz requested. There is practically no change in the performance of hash to curve: |
han0110
left a comment
There was a problem hiding this comment.
LGTM! Some nitpicks that could be ignored.
- Add Legendre macro with norm and legendre symbol computation - Add macro for automatic implementation in prime fields
c2af9ed to
5e7022c
Compare
* Add field conversion to/from `[u64;4]` (privacy-ethereum#80) * feat: add field conversion to/from `[u64;4]` * Added conversion tests * Added `montgomery_reduce_short` for no-asm * For bn256, uses assembly conversion when asm feature is on * fix: remove conflict for asm * chore: bump rust-toolchain to 1.67.0 * Compute Legendre symbol for `hash_to_curve` (privacy-ethereum#77) * Add `Legendre` trait and macro - Add Legendre macro with norm and legendre symbol computation - Add macro for automatic implementation in prime fields * Add legendre macro call for prime fields * Remove unused imports * Remove leftover * Add `is_quadratic_non_residue` for hash_to_curve * Add `legendre` function * Compute modulus separately * Substitute division for shift * Update modulus computation * Add quadratic residue check func * Add quadratic residue tests * Add hash_to_curve bench * Implement Legendre trait for all curves * Move misplaced comment * Add all curves to hash bench * fix: add suggestion for legendre_exp * fix: imports after rebase * Add simplified SWU method (privacy-ethereum#81) * Fix broken link * Add simple SWU algorithm * Add simplified SWU hash_to_curve for secp256r1 * add: sswu z reference * update MAP_ID identifier Co-authored-by: Han <tinghan0110@gmail.com> --------- Co-authored-by: Han <tinghan0110@gmail.com> * Bring back curve algorithms for `a = 0` (privacy-ethereum#82) * refactor: bring back curve algorithms for `a = 0` * fix: clippy warning * fix: Improve serialization for prime fields (privacy-ethereum#85) * fix: Improve serialization for prime fields Summary: 256-bit field serialization is currently 4x u64, ie. the native format. This implements the standard of byte-serialization (corresponding to the PrimeField::{to,from}_repr), and an hex-encoded variant of that for (de)serializers that are human-readable (concretely, json). - Added a new macro `serialize_deserialize_32_byte_primefield!` for custom serialization and deserialization of 32-byte prime field in different struct (Fq, Fp, Fr) across the secp256r, bn256, and derive libraries. - Implemented the new macro for serialization and deserialization in various structs, replacing the previous `serde::{Deserialize, Serialize}` direct use. - Enhanced error checking in the custom serialization methods to ensure valid field elements. - Updated the test function in the tests/field.rs file to include JSON serialization and deserialization tests for object integrity checking. * fixup! fix: Improve serialization for prime fields --------- Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com> * refactor: (De)Serialization of points using `GroupEncoding` (privacy-ethereum#88) * refactor: implement (De)Serialization of points using the `GroupEncoding` trait - Updated curve point (de)serialization logic from the internal representation to the representation offered by the implementation of the `GroupEncoding` trait. * fix: add explicit json serde tests * Insert MSM and FFT code and their benchmarks. (privacy-ethereum#86) * Insert MSM and FFT code and their benchmarks. Resolves taikoxyz/zkevm-circuits#150. * feedback * Add instructions * feeback * Implement feedback: Actually supply the correct arguments to `best_multiexp`. Split into `singlecore` and `multicore` benchmarks so Criterion's result caching and comparison over multiple runs makes sense. Rewrite point and scalar generation. * Use slicing and parallelism to to decrease running time. Laptop measurements: k=22: 109 sec k=16: 1 sec * Refactor msm * Refactor fft * Update module comments * Fix formatting * Implement suggestion for fixing CI --------- Co-authored-by: David Nevado <davidnevadoc@users.noreply.github.com> Co-authored-by: Han <tinghan0110@gmail.com> Co-authored-by: François Garillot <4142+huitseeker@users.noreply.github.com> Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com> Co-authored-by: einar-taiko <126954546+einar-taiko@users.noreply.github.com>
* Add field conversion to/from `[u64;4]` (privacy-ethereum#80) * feat: add field conversion to/from `[u64;4]` * Added conversion tests * Added `montgomery_reduce_short` for no-asm * For bn256, uses assembly conversion when asm feature is on * fix: remove conflict for asm * chore: bump rust-toolchain to 1.67.0 * Compute Legendre symbol for `hash_to_curve` (privacy-ethereum#77) * Add `Legendre` trait and macro - Add Legendre macro with norm and legendre symbol computation - Add macro for automatic implementation in prime fields * Add legendre macro call for prime fields * Remove unused imports * Remove leftover * Add `is_quadratic_non_residue` for hash_to_curve * Add `legendre` function * Compute modulus separately * Substitute division for shift * Update modulus computation * Add quadratic residue check func * Add quadratic residue tests * Add hash_to_curve bench * Implement Legendre trait for all curves * Move misplaced comment * Add all curves to hash bench * fix: add suggestion for legendre_exp * fix: imports after rebase * Add simplified SWU method (privacy-ethereum#81) * Fix broken link * Add simple SWU algorithm * Add simplified SWU hash_to_curve for secp256r1 * add: sswu z reference * update MAP_ID identifier Co-authored-by: Han <tinghan0110@gmail.com> --------- Co-authored-by: Han <tinghan0110@gmail.com> * Bring back curve algorithms for `a = 0` (privacy-ethereum#82) * refactor: bring back curve algorithms for `a = 0` * fix: clippy warning * fix: Improve serialization for prime fields (privacy-ethereum#85) * fix: Improve serialization for prime fields Summary: 256-bit field serialization is currently 4x u64, ie. the native format. This implements the standard of byte-serialization (corresponding to the PrimeField::{to,from}_repr), and an hex-encoded variant of that for (de)serializers that are human-readable (concretely, json). - Added a new macro `serialize_deserialize_32_byte_primefield!` for custom serialization and deserialization of 32-byte prime field in different struct (Fq, Fp, Fr) across the secp256r, bn256, and derive libraries. - Implemented the new macro for serialization and deserialization in various structs, replacing the previous `serde::{Deserialize, Serialize}` direct use. - Enhanced error checking in the custom serialization methods to ensure valid field elements. - Updated the test function in the tests/field.rs file to include JSON serialization and deserialization tests for object integrity checking. * fixup! fix: Improve serialization for prime fields --------- Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com> * refactor: (De)Serialization of points using `GroupEncoding` (privacy-ethereum#88) * refactor: implement (De)Serialization of points using the `GroupEncoding` trait - Updated curve point (de)serialization logic from the internal representation to the representation offered by the implementation of the `GroupEncoding` trait. * fix: add explicit json serde tests * Insert MSM and FFT code and their benchmarks. (privacy-ethereum#86) * Insert MSM and FFT code and their benchmarks. Resolves taikoxyz/zkevm-circuits#150. * feedback * Add instructions * feeback * Implement feedback: Actually supply the correct arguments to `best_multiexp`. Split into `singlecore` and `multicore` benchmarks so Criterion's result caching and comparison over multiple runs makes sense. Rewrite point and scalar generation. * Use slicing and parallelism to to decrease running time. Laptop measurements: k=22: 109 sec k=16: 1 sec * Refactor msm * Refactor fft * Update module comments * Fix formatting * Implement suggestion for fixing CI * Re-export also mod `pairing` and remove flag `reexport` to alwasy re-export (privacy-ethereum#93) fix: re-export also mod `pairing` and remove flag `reexport` to alwasy re-export * fix regression in privacy-ethereum#93 reexport field benches aren't run (privacy-ethereum#94) fix regression in privacy-ethereum#93, field benches aren't run * Fast modular inverse - 9.4x acceleration (privacy-ethereum#83) * Bernstein yang modular multiplicative inverter (#2) * rename similar to privacy-ethereum#95 --------- Co-authored-by: Aleksei Vambol <77882392+AlekseiVambol@users.noreply.github.com> * Fast isSquare / Legendre symbol / Jacobi symbol - 16.8x acceleration (privacy-ethereum#95) * Derivatives of the Pornin's method (taikoxyz#3) * renaming file * make cargo fmt happy * clarifications from privacy-ethereum#95 (comment) [skip ci] * Formatting and slightly changing a comment --------- Co-authored-by: Aleksei Vambol <77882392+AlekseiVambol@users.noreply.github.com> * chore: delete bernsteinyang module (replaced by ff_inverse) * Bump version to 0.4.1 --------- Co-authored-by: David Nevado <davidnevadoc@users.noreply.github.com> Co-authored-by: Han <tinghan0110@gmail.com> Co-authored-by: François Garillot <4142+huitseeker@users.noreply.github.com> Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com> Co-authored-by: einar-taiko <126954546+einar-taiko@users.noreply.github.com> Co-authored-by: Mamy Ratsimbazafy <mamy_github@numforge.co> Co-authored-by: Aleksei Vambol <77882392+AlekseiVambol@users.noreply.github.com>
This is an attempt to close #73 .
Unlike in Arkworks, I believe there is no clean way to access the modulus p of a PrimeField here. I have gotten it using:
although in the docs it is explicitly mentioned that:
Suggestions for alternative approaches are welcome.
Update:
MODULUS - 1value is now obtained by getting the representation of-F::ONEso the method above can be avoided. (Thanks to @huitseeker for the suggestion).